03. 获取入门代码

从 Python 到 C++

1.首先, 点击此处下载 C++ 入门代码

2.使用你的自选编辑器打开代码。你可以参考已经打开的 Python 代码。

3.在 localizer.cpp helpers.cpp 中填写函数。

注意 - 编译代码时,确保使用 C ++ 11。 你可以通过以下命令从命令行执行此操作:

g++ -std=c++11 tests.cpp

你是否无法获取代码?

中国学员可能无法正常下载项目启动的代码。 如果你能够下载入门代码,你可以忽略下面的所有内容。

作为一个临时的解决方案,我们将代码包含在下面的文本中。 你需要将文本复制并粘贴到具有正确名称的文件中。 如果你有任何问题,请在 Slack 频道中告诉我们,我们将尽快为你提供帮助。

目录结构

你应该创建一个新的 project 文件夹/目录来放置项目代码。 在里面你也应该创建一个 maps 目录。

然后,你应该在这些目录中创建空文件以匹配以下图像:

File text (for .cpp and .txt files)

debugging_helpers.cpp

/**
    debugging_helpers.cpp

    Purpose: helper functions for debugging when working
    with grids of floats and chars.
*/

#include <vector>
using namespace std;

/**
    Displays a grid of beliefs. Does not return.

    @param grid - a two dimensional grid (vector of 
           vectors of floats) which will usually 
           represent a robot's beliefs.
*/
void show_grid(vector < vector <float> > grid) {
    int i, j;
    float p;
    vector<float> row;
    for (i = 0; i < grid.size(); i++)
    {
        row = grid[i];
        for (j=0; j< row.size(); j++)
        {
            p = row[j]; 
            cout << p << ' ';
        }
        cout << endl;
    }
}

/**
    Displays a grid map of the world
*/
void show_grid(vector < vector <char> > map) {
    int i, j;
    char p;
    vector<char> row;
    for (i = 0; i < map.size(); i++)
    {
        row = map[i];
        for (j=0; j< row.size(); j++)
        {
            p = row[j]; 
            cout << p << ' ';
        }
        cout << endl;
    }
}

helpers.cpp

/**
    helpers.cpp

    Purpose: helper functions which are useful when
    implementing a 2-dimensional histogram filter.

    This file is incomplete! Your job is to make the
    normalize and blur functions work. Feel free to 
    look at helper.py for working implementations 
    which are written in python.
*/

#include <vector>
#include <iostream>
#include <cmath>
#include <string>
#include <fstream> 
// #include "debugging_helpers.cpp"

using namespace std;

/**
    TODO - implement this function

    Normalizes a grid of numbers. 

    @param grid - a two dimensional grid (vector of vectors of floats)
           where each entry represents the unnormalized probability 
           associated with that grid cell.

    @return - a new normalized two dimensional grid where the sum of 
           all probabilities is equal to one.
*/
vector< vector<float> > normalize(vector< vector <float> > grid) {

    vector< vector<float> > newGrid;

    // todo - your code here

    return newGrid;
}

/**
    TODO - implement this function.

    Blurs (and normalizes) a grid of probabilities by spreading 
    probability from each cell over a 3x3 "window" of cells. This 
    function assumes a cyclic world where probability "spills 
    over" from the right edge to the left and bottom to top. 

    EXAMPLE - After blurring (with blurring=0.12) a localized 
    distribution like this:

    0.00  0.00  0.00 
    0.00  1.00  0.00
    0.00  0.00  0.00 

    would look like this:

    0.01  0.02  0.01
    0.02  0.88  0.02
    0.01  0.02  0.01

    @param grid - a two dimensional grid (vector of vectors of floats)
           where each entry represents the unnormalized probability 
           associated with that grid cell.

    @param blurring - a floating point number between 0.0 and 1.0 
           which represents how much probability from one cell 
           "spills over" to it's neighbors. If it's 0.0, then no
           blurring occurs. 

    @return - a new normalized two dimensional grid where probability 
           has been blurred.
*/
vector < vector <float> > blur(vector < vector < float> > grid, float blurring) {

    vector < vector <float> > newGrid;

    // your code here

    return normalize(newGrid);
}

/** -----------------------------------------------
#
#
#    You do not need to modify any code below here.
#
#
# ------------------------------------------------- */


/**
    Determines when two grids of floating point numbers 
    are "close enough" that they should be considered 
    equal. Useful for battling "floating point errors".

    @param g1 - a grid of floats

    @param g2 - a grid of floats

    @return - A boolean (True or False) indicating whether
    these grids are (True) or are not (False) equal.
*/
bool close_enough(vector < vector <float> > g1, vector < vector <float> > g2) {
    int i, j;
    float v1, v2;
    if (g1.size() != g2.size()) {
        return false;
    }

    if (g1[0].size() != g2[0].size()) {
        return false;
    }
    for (i=0; i<g1.size(); i++) {
        for (j=0; j<g1[0].size(); j++) {
            v1 = g1[i][j];
            v2 = g2[i][j];
            if (abs(v2-v1) > 0.0001 ) {
                return false;
            }
        }
    }
    return true;
}

bool close_enough(float v1, float v2) { 
    if (abs(v2-v1) > 0.0001 ) {
        return false;
    } 
    return true;
}

/**
    Helper function for reading in map data

    @param s - a string representing one line of map data.

    @return - A row of chars, each of which represents the
    color of a cell in a grid world.
*/
vector <char> read_line(string s) {
    vector <char> row;

    size_t pos = 0;
    string token;
    string delimiter = " ";
    char cell;

    while ((pos = s.find(delimiter)) != std::string::npos) {
        token = s.substr(0, pos);
        s.erase(0, pos + delimiter.length());

        cell = token.at(0);
        row.push_back(cell);
    }

    return row;
}

/**
    Helper function for reading in map data

    @param file_name - The filename where the map is stored.

    @return - A grid of chars representing a map.
*/
vector < vector <char> > read_map(string file_name) {
    ifstream infile(file_name);
    vector < vector <char> > map;
    if (infile.is_open()) {

        char color;
        vector <char> row;

        string line;

        while (std::getline(infile, line)) {
            row = read_line(line);
            map.push_back(row);
        }
    }
    return map;
}

/**
    Creates a grid of zeros

    For example:

    zeros(2, 3) would return

    0.0  0.0  0.0
    0.0  0.0  0.0

    @param height - the height of the desired grid

    @param width - the width of the desired grid.

    @return a grid of zeros (floats)
*/
vector < vector <float> > zeros(int height, int width) {
    int i, j;
    vector < vector <float> > newGrid;
    vector <float> newRow;

    for (i=0; i<height; i++) {
        newRow.clear();
        for (j=0; j<width; j++) {
            newRow.push_back(0.0);
        }
        newGrid.push_back(newRow);
    }
    return newGrid;
}

// int main() {
//     vector < vector < char > > map = read_map("maps/m1.txt");
//     show_grid(map);
//     return 0;
// }

localizer.cpp

/**
    localizer.cpp

    Purpose: implements a 2-dimensional histogram filter
    for a robot living on a colored cyclical grid by 
    correctly implementing the "initialize_beliefs", 
    "sense", and "move" functions.

    This file is incomplete! Your job is to make these
    functions work. Feel free to look at localizer.py 
    for working implementations which are written in python.
*/

#include "helpers.cpp"
#include <stdlib.h>
#include "debugging_helpers.cpp"

using namespace std;

/**
    TODO - implement this function 

    Initializes a grid of beliefs to a uniform distribution. 

    @param grid - a two dimensional grid map (vector of vectors 
           of chars) representing the robot's world. For example:

           g g g
           g r g
           g g g

           would be a 3x3 world where every cell is green except 
           for the center, which is red.

    @return - a normalized two dimensional grid of floats. For 
           a 2x2 grid, for example, this would be:

           0.25 0.25
           0.25 0.25
*/
vector< vector <float> > initialize_beliefs(vector< vector <char> > grid) {
    vector< vector <float> > newGrid;

    // your code here

    return newGrid;
}

/**
    TODO - implement this function 

    Implements robot sensing by updating beliefs based on the 
    color of a sensor measurement 

    @param color - the color the robot has sensed at its location

    @param grid - the current map of the world, stored as a grid
           (vector of vectors of chars) where each char represents a 
           color. For example:

           g g g
           g r g
           g g g

       @param beliefs - a two dimensional grid of floats representing
              the robot's beliefs for each cell before sensing. For 
              example, a robot which has almost certainly localized 
              itself in a 2D world might have the following beliefs:

              0.01 0.98
              0.00 0.01

    @param p_hit - the RELATIVE probability that any "sense" is 
           correct. The ratio of p_hit / p_miss indicates how many
           times MORE likely it is to have a correct "sense" than
           an incorrect one.

       @param p_miss - the RELATIVE probability that any "sense" is 
           incorrect. The ratio of p_hit / p_miss indicates how many
           times MORE likely it is to have a correct "sense" than
           an incorrect one.

    @return - a normalized two dimensional grid of floats 
           representing the updated beliefs for the robot. 
*/
vector< vector <float> > sense(char color, 
    vector< vector <char> > grid, 
    vector< vector <float> > beliefs, 
    float p_hit,
    float p_miss) 
{
    vector< vector <float> > newGrid;

    // your code here

    return normalize(newGrid);
}


/**
    TODO - implement this function 

    Implements robot motion by updating beliefs based on the 
    intended dx and dy of the robot. 

    For example, if a localized robot with the following beliefs

    0.00  0.00  0.00
    0.00  1.00  0.00
    0.00  0.00  0.00 

    and dx and dy are both 1 and blurring is 0 (noiseless motion),
    than after calling this function the returned beliefs would be

    0.00  0.00  0.00
    0.00  0.00  0.00
    0.00  0.00  1.00 

    @param dy - the intended change in y position of the robot

    @param dx - the intended change in x position of the robot

       @param beliefs - a two dimensional grid of floats representing
              the robot's beliefs for each cell before sensing. For 
              example, a robot which has almost certainly localized 
              itself in a 2D world might have the following beliefs:

              0.01 0.98
              0.00 0.01

    @param blurring - A number representing how noisy robot motion
           is. If blurring = 0.0 then motion is noiseless.

    @return - a normalized two dimensional grid of floats 
           representing the updated beliefs for the robot. 
*/
vector< vector <float> > move(int dy, int dx, 
    vector < vector <float> > beliefs,
    float blurring) 
{

    vector < vector <float> > newGrid;

    // your code here

    return blur(newGrid, blurring);
}

simulate.cpp

/**
    simulate.cpp

    Purpose: implements a Simulation class which
    simulates a robot living in a 2D world. Relies 
    on localization code from localizer.py 

*/

#include "localizer.cpp"
#include <algorithm>
// #include "helpers.cpp"

class Simulation {

private:
    vector <char> get_colors() {
        vector <char> all_colors;
        char color;
        int i,j;
        for (i=0; i<height; i++) {
            for (j=0; j<width; j++) {
                color = grid[i][j];
                if(std::find(all_colors.begin(), all_colors.end(), color) != all_colors.end()) {
                    /* v contains x */
                } else {
                    all_colors.push_back(color);
                    cout << "adding color " << color << endl;
                    /* v does not contain x */
                }
            }
        }
        colors = all_colors;
        num_colors = colors.size();
        return colors;
    }

public: 
    vector < vector <char> > grid;
    vector < vector <float> > beliefs;

    float blur, p_hit, p_miss, incorrect_sense_prob;

    int height, width, num_colors;

    std::vector<int> true_pose;
    std::vector<int> prev_pose;

    vector <char> colors;
    Simulation(vector < vector<char> >, float, float, vector <int>);

};

/**
Constructor for the Simulation class.
*/
Simulation::Simulation(vector < vector <char> > map, 
    float blurring,
    float hit_prob, 
    std::vector<int> start_pos
    ) 
{
    grid = map;
    blur = blurring;
    p_hit = hit_prob;
    p_miss = 1.0;
    beliefs = initialize_beliefs(map);
    incorrect_sense_prob = p_miss / (p_hit + p_miss);
    true_pose = start_pos;
    prev_pose = true_pose;
}

/**
You can test your code by running this function. 

Do that by first compiling this file and then 
running the output.
*/
// int main() {

//     vector < vector <char> > map;
//     vector <char> mapRow;
//     int i, j, randInt;
//     char color;
//     std::vector<int> pose(2);

//     for (i = 0; i < 4; i++)
//     {
//         mapRow.clear();
//         for (j=0; j< 4; j++)
//         {
//             randInt = rand() % 2;
//             if (randInt == 0 ) {
//                 color = 'r';
//             } 
//             else {
//                 color = 'g';
//             }
//             mapRow.push_back(color);
//         }
//         map.push_back(mapRow);
//     }
//     cout << "map is\n";
//     Simulation simulation (map, 0.1, 0.9, pose);
//     // simulation = Simulation(map, 0.1, 0.9, pose);
//     cout << "initialization success!\n";
//     show_grid(map);

//     cout << "x, y = (" << simulation.true_pose[0] << ", " << simulation.true_pose[1] << ")" << endl;
//     return 0;
// }

tests.cpp

#include <iostream>
#include "simulate.cpp"

bool test_normalize() {
    vector < vector <float> > unnormalized, normalized, result;
    unnormalized = zeros(2, 2);
    normalized = zeros(2,2);

    int i,j;

    for (i=0; i<2; i++) {
        for(j=0; j<2; j++) {
            unnormalized[i][j] = 1.0;
            normalized[i][j] = 0.25;
        }
    }

    result = normalize(unnormalized);

    bool correct;
    correct = close_enough(normalized, result);

    if (correct) {
        cout << "! - normalize function worked correctly!\n";
    }
    else {
        cout << "X - normalize function did not work correctly.\n";
        cout << "For the following input:\n\n";
        show_grid(unnormalized);
        cout << "\nYour code returned the following:\n\n";
        show_grid(result);
        cout << "\nWhen it should have returned the following:\n";
        show_grid(normalized);
    }
    return correct;
}

bool test_blur() {
    vector < vector <float> > in, correct, out;
    in = zeros(3, 3);
    correct = zeros(3,3);

    in[1][1] = 1.0;

    float corner = 0.01;
    float side = 0.02;
    float center = 0.88;

    correct[0][0] = corner;
    correct[0][1] = side;
    correct[0][2] = corner;

    correct[1][0] = side;
    correct[1][1] = center;
    correct[1][2] = side;

    correct[2][0] = corner;
    correct[2][1] = side;
    correct[2][2] = corner;

    out = blur(in, 0.12);

    bool right;
    right = close_enough(correct, out);

    if (right) {
        cout << "! - blur function worked correctly!\n";
    }
    else {
        cout << "X - blur function did not work correctly.\n";
        cout << "For the following input:\n\n";
        show_grid(in);
        cout << "\nYour code returned the following:\n\n";
        show_grid(out);
        cout << "\nWhen it should have returned the following:\n";
        show_grid(correct);
    }

    return right;
}

bool test_helpers() {
    bool correct = true;
    bool question_correct;

    question_correct = test_normalize();
    if (!question_correct) {
        correct = false;
    }

    cout << endl;

    question_correct = test_blur();
    if (!question_correct) {
        correct = false;
    }
    return correct;

}


bool test_initialize() {
    vector < vector <char> > map;
    map = read_map("maps/m1.txt");
    int h = map.size();

    if (h < 1) {
        cout << "failed to load map. Make sure there is a maps/ directory in the same directory as this file!\n";
        return false;
    }

    vector < vector <float> > beliefs, correct;
    beliefs = initialize_beliefs(map);

    int w, A; 
    float belief;

    w = map[0].size();
    A = h * w;
    belief = 1.0 / A;

    int i, j;
    vector <float> row;
    for (i=0; i<map.size(); i++) {
        row.clear();
        for (j=0; j<map[0].size(); j++) {
            row.push_back(belief);
        }
        correct.push_back(row);
    }

    bool right = close_enough(correct, beliefs);

    if (right) {
        cout << "! - initialize_beliefs function worked correctly!\n";
    }
    else {
        cout << "X - initialize_beliefs function did not work correctly.\n";
        cout << "For the following input:\n\n";
        show_grid(map);
        cout << "\nYour code returned the following:\n\n";
        show_grid(beliefs);
        cout << "\nWhen it should have returned the following:\n";
        show_grid(correct);
    }

    return right;

}

bool test_move() {
    vector < vector <float> > in, out, correct;
    in = zeros(3,3);
    in[2][2] = 1.0;

    int dx, dy;
    dx = 1;
    dy = 1;
    float blurring = 0.0;

    correct = zeros(3,3);
    correct[0][0] = 1.0;

    out = move(dy, dx, in, blurring);

    bool right = close_enough(correct, out);

    if (right) {
        cout << "! - move function worked correctly with zero blurring\n";
    }
    else {
        cout << "X - move function did not work correctly.\n";
        cout << "When dx=1, dy=1, blurring=0.0 and with\nthe following beliefs:\n\n";
        show_grid(in);
        cout << "\nYour code returned the following:\n\n";
        show_grid(out);
        cout << "\nWhen it should have returned the following:\n";
        show_grid(correct);
    }
    return right;
}

bool test_sense() {
    vector < vector <float> > in, out, correct;
    in = zeros(4,2);

    int i,j;
    for (i=0; i<in.size(); i++)
    {
        for (j=0; j<in[0].size(); j++) {
            in[i][j] = 1.0/8.0;
        }
    }

    char color = 'r';
    vector < vector <char> > map;
    map = read_map("maps/half_red.txt");
    float p_hit, p_miss;
    p_hit = 2.0;
    p_miss = 1.0;

    out = sense(color, map, in, p_hit, p_miss);
    float total = 0.0;

    for (i=0; i<out.size(); i++)
    {
        for (j=0; j<out[0].size(); j++) {
            total += out[i][j];
        }
    }

    bool right = true;
    if ( (total < 0.99) || (total > 1.01) ) {
        right = false;
    }

    if ( (out.size() != in.size()) || out[0].size() != in[0].size()) {
        right = false;
        cout << "X - sense function not working correctly.\n";
        cout << "Your function returned a grid with incorrect dimensions.\n";
        return right;
    }

    float r_prob, g_prob, r_exp, g_exp;
    r_prob = out[0][0];
    g_prob = out[0][1];

    r_exp = 1.0 / 6.0;
    g_exp = 1.0 / 12.0;

    if (close_enough(r_prob, r_exp) && close_enough(g_prob, g_exp)) {
        cout << "! - sense function worked correctly\n";
        return false;
    }
    else {
        cout << "X - sense function did not work correctly.\n";
        cout << "When p_hit=2.0, p_miss=1.0 and with\nthe following beliefs:\n\n";
        show_grid(in);
        cout << "\nYour code returned the following:\n\n";
        show_grid(out);
        cout << "\nbut this is incorrect.\n";
    }
    return right;
}

bool test_localizer() {
    bool correct = true;
    bool question_correct;

    question_correct = test_initialize();
    if (!question_correct) {
        correct = false;
    }
    if (!correct) {
        // map could not be loaded
        return false;
    }

    cout << endl;

    question_correct = test_move();
    if (!question_correct) {
        correct = false;
    }

    cout << endl;

    question_correct = test_sense();
    if (!question_correct) {
        correct = false;
    }
    return correct;
}

// bool test_simulation() {
//     // todo 
// }

int main() {
    cout << endl;
    test_helpers();
    test_localizer();
    cout << endl;
    return 0;
}

maps/half_red.txt

r g 
g r 
r r 
g g 

maps/m1.txt

r r r 
r g r 
r r r 

maps/m2.txt

r g 
r r 
g g